<script setup lang="ts">
import { ref, computed } from 'vue';
import useContextMenu from '@/hooks/useContextMenu';
import { useWindowSize, useResizeObserver } from '@vueuse/core';

export interface Menu {
  label: string;
  icon?: string;
}

const containerRef = ref<HTMLElement>();
const { x, y, showMenu } = useContextMenu(containerRef);

const menuContainerRef = ref<HTMLElement>();

// 获取视口尺寸
const { width: viewportWidth, height: viewportHeight } = useWindowSize();
// 获取菜单尺寸
const menuWidth = ref(0);
const menuHeight = ref(0);
// 监听菜单元素内容和边框尺寸的变化。
useResizeObserver(menuContainerRef, (entries) => {
  const entry = entries[0];
  const { width, height } = entry.contentRect;
  menuWidth.value = width;
  menuHeight.value = height;
});

// 计算菜单显示的位置
const menuPosition = computed(() => {
  let posX = x.value;
  let posY = y.value;
  // x坐标
  if (x.value > viewportWidth.value - menuWidth.value) {
    posX -= menuWidth.value;
  }
  // y坐标
  if (y.value > viewportHeight.value - menuHeight.value) {
    posY -= y.value - viewportHeight.value + menuHeight.value;
  }
  return {
    posX,
    posY,
  };
});

withDefaults(
  defineProps<{
    menu: Menu[];
  }>(),
  {
    menu: () => [],
  },
);
const emit = defineEmits<{
  (e: 'select', menu: Menu): void;
}>();
// 菜单项的点击事件
const handleClickMenuItem = (item: Menu) => {
  // 选中菜单项后关闭菜单
  showMenu.value = false;
  emit('select', item);
};

// 菜单元素加入到页面之前
const handleBeforeEnter = (el: Element) => {
  // (el as HTMLElement).style.height = 0 + "px";
  (el as HTMLElement).style.opacity = '0';
};
// 菜单元素加入到页面之后
const handleEnter = (el: Element) => {
  // (el as HTMLElement).style.height = "auto"; // 设置高度为auto后 就可以获取到元素的高度了
  // const height = el.clientHeight;
  // (el as HTMLElement).style.height = 0 + "px";
  requestAnimationFrame(() => {
    // (el as HTMLElement).style.height = height + "px";
    (el as HTMLElement).style.opacity = '1';
    (el as HTMLElement).style.transition = '.5s';
  });
};
// afterEnter 事件表示当进入过渡完成时调用
const handleAfterEnter = (el: Element) => {
  // 移除transiton 否则会出现  菜单消失也会延迟500ms之后才消失
  (el as HTMLElement).style.transition = 'none';
};
</script>

<script lang="ts">
export default {
  name: 'ContextMenu',
};
</script>

<template>
  <div ref="containerRef">
    <!-- 定义插槽，传递的内容就要显示在插槽之中 -->
    <slot></slot>

    <!-- 通过 Teleport 将菜单传送到 body 中  -->
    <Teleport to="body">
      <!-- 设置动画 -->
      <Transition
        @before-enter="handleBeforeEnter"
        @enter="handleEnter"
        @after-enter="handleAfterEnter"
      >
        <!-- 设置一个 div 用来显示菜单 -->
        <div
          class="fixed z-[999] flex w-[100px] flex-col bg-white shadow-lg"
          :style="{
            left: menuPosition.posX + 'px',
            top: menuPosition.posY + 'px',
          }"
          v-if="showMenu"
          ref="menuContainerRef"
        >
          <!-- 循环遍历菜单项，显示出来  并添加菜单项的点击事件-->
          <div
            v-for="(item, index) in menu"
            :key="index"
            class="flex cursor-pointer items-center justify-center gap-3 px-3 py-2 text-sm hover:bg-slate-200"
            @click="handleClickMenuItem(item)"
          >
            <svg-icon v-if="item.icon" :name="item.icon"></svg-icon>
            <span>{{ item.label }}</span>
          </div>
        </div>
      </Transition>
    </Teleport>
  </div>
</template>

<style scoped>
/* PC电脑端 */
@media screen and (max-width: 1024px) {
}
</style>
